package com.runa.protocol.util;

import com.runa.protocol.enums.ByteOrder;
import org.apache.commons.lang3.ArrayUtils;

public class ByteUtil {


    public static byte[] slice(byte[] bs, int offset, int len) {
        byte[] r = new byte[len];
        System.arraycopy(bs, offset, r, 0, len);
        return r;
    }

    public static byte[] merge(byte[]... bss) {
        byte[] res = bss[0];
        for (int i = 1; i < bss.length; i++) {
            if (res == null || res.length == 0) {
                res = bss[i];
            } else if (bss[i] != null && bss[i].length > 0) {
                res = ArrayUtils.addAll(res, bss[i]);
            }
        }
        return res;
    }

    /**
     * Convert long to byte array.
     *
     * @param number The data to be converted.
     * @return 8-digit byte array.
     */
    public static byte[] longToByte(long number) {
        long temp = number;
        byte[] b = new byte[8];
        return getBytes(temp, b);
    }

    private static byte[] getBytes(long temp, byte[] b) {
        for (int i = 0; i < b.length; i++) {
            b[i] = Long.valueOf(temp & 0xff).byteValue();
            temp = temp >> 8;
        }
        return b;
    }

    /**
     * Convert byte array to long.
     *
     * @param b The byte array to be converted.
     * @return
     */
    public static long byteToLong(byte[] b, int offset, ByteOrder byteOrder) {
        long s;
        long s0 = 0;
        long s1 = 0;
        long s2 = 0;
        long s3 = 0;
        long s4 = 0;
        long s5 = 0;
        long s6 = 0;
        long s7 = 0;
        switch (byteOrder) {
            case ABCDEFGH:
                s0 = b[7 + offset] & 0xff;
                s1 = b[6 + offset] & 0xff;
                s2 = b[5 + offset] & 0xff;
                s3 = b[4 + offset] & 0xff;
                s4 = b[3 + offset] & 0xff;
                s5 = b[2 + offset] & 0xff;
                s6 = b[1 + offset] & 0xff;
                s7 = b[0 + offset] & 0xff;
                break;
            case BADCFEHG:
                s0 = b[6 + offset] & 0xff;
                s1 = b[7 + offset] & 0xff;
                s2 = b[4 + offset] & 0xff;
                s3 = b[5 + offset] & 0xff;
                s4 = b[2 + offset] & 0xff;
                s5 = b[3 + offset] & 0xff;
                s6 = b[0 + offset] & 0xff;
                s7 = b[1 + offset] & 0xff;
                break;
            case GHEFCDAB:
                s0 = b[1 + offset] & 0xff;
                s1 = b[0 + offset] & 0xff;
                s2 = b[3 + offset] & 0xff;
                s3 = b[2 + offset] & 0xff;
                s4 = b[5 + offset] & 0xff;
                s5 = b[4 + offset] & 0xff;
                s6 = b[7 + offset] & 0xff;
                s7 = b[6 + offset] & 0xff;
                break;
            case HGFEDCBA:
                s0 = b[0 + offset] & 0xff;
                s1 = b[1 + offset] & 0xff;
                s2 = b[2 + offset] & 0xff;
                s3 = b[3 + offset] & 0xff;
                s4 = b[4 + offset] & 0xff;
                s5 = b[5 + offset] & 0xff;
                s6 = b[6 + offset] & 0xff;
                s7 = b[7 + offset] & 0xff;
        }
        s1 <<= 8;
        s2 <<= 16;
        s3 <<= 24;
        s4 <<= 8 * 4;
        s5 <<= 8 * 5;
        s6 <<= 8 * 6;
        s7 <<= 8 * 7;
        s = s0 | s1 | s2 | s3 | s4 | s5 | s6 | s7;
        return s;
    }

    /**
     * Convert int to byte array.
     *
     * @param number The int value to be converted.
     * @return
     */
    public static byte[] intToByte(int number) {
        int temp = number;
        byte[] b = new byte[4];
        return getBytes(temp, b);
    }

    /**
     * @param number
     * @param buf
     * @param offSet
     * @param byteOrder
     */
    public static void intToByte(int number, byte[] buf, int offSet, ByteOrder byteOrder) {
        byte d = (byte) (number & 0xff);
        byte c = (byte) ((number >> 8) & 0xff);
        byte b = (byte) ((number >> 16) & 0xff);
        byte a = (byte) ((number >> 24) & 0xff);
        switch (byteOrder) {
            case DCBA:
                buf[offSet] = d;
                buf[offSet + 1] = c;
                buf[offSet + 2] = b;
                buf[offSet + 3] = a;
                break;
            case CDAB:
                buf[offSet] = c;
                buf[offSet + 1] = d;
                buf[offSet + 2] = a;
                buf[offSet + 3] = b;
                break;
            case ABCD:
                buf[offSet] = a;
                buf[offSet + 1] = b;
                buf[offSet + 2] = c;
                buf[offSet + 3] = d;
                break;
            case BADC:
                buf[offSet] = b;
                buf[offSet + 1] = a;
                buf[offSet + 2] = d;
                buf[offSet + 3] = c;
                break;
            default:
                //throw
                break;
        }
    }

    public static byte[] intToByte(int number, ByteOrder byteOrder) {
        byte[] buf = new byte[4];
        int offSet = 0;
        byte d = (byte) (number & 0xff);
        byte c = (byte) ((number >> 8) & 0xff);
        byte b = (byte) ((number >> 16) & 0xff);
        byte a = (byte) ((number >> 24) & 0xff);
        switch (byteOrder) {
            case DCBA:
                buf[offSet] = d;
                buf[offSet + 1] = c;
                buf[offSet + 2] = b;
                buf[offSet + 3] = a;
                break;
            case CDAB:
                buf[offSet] = c;
                buf[offSet + 1] = d;
                buf[offSet + 2] = a;
                buf[offSet + 3] = b;
                break;
            case ABCD:
                buf[offSet] = a;
                buf[offSet + 1] = b;
                buf[offSet + 2] = c;
                buf[offSet + 3] = d;
                break;
            case BADC:
                buf[offSet] = b;
                buf[offSet + 1] = a;
                buf[offSet + 2] = d;
                buf[offSet + 3] = c;
                break;
            default:
                //throw
                break;
        }
        return buf;
    }

    public static Integer byte3ToInt(byte[] b, int offset, boolean reverse) {
        int s;
        int s0 = 0;
        int s1 = 0;
        int s2 = 0;
        int s3 = 0;
        if (reverse) {
            s0 = b[0+offset] & 0xff;
            s1 = b[1+offset] & 0xff;
            s2 = b[2+offset] & 0xff;
            s3 <<= 24;
            s2 <<= 16;
            s1 <<= 8;
        } else {
            s1 = b[0+offset] & 0xff;
            s2 = b[1+offset] & 0xff;
            s3 = b[2+offset] & 0xff;
            s0 <<= 24;
            s1 <<= 16;
            s2 <<= 8;
        }
        s = s0 | s1 | s2 | s3;
        return s;
    }

    /**
     * Convert byte array to int.
     *
     * @param b
     * @return
     */
    public static Integer byteToInt(byte[] b, ByteOrder byteOrder) {
        int s;
        int s0 = b[0] & 0xff;
        int s1 = b[1] & 0xff;
        int s2 = b[2] & 0xff;
        int s3 = b[3] & 0xff;
        switch (byteOrder) {
            case DCBA:
                s3 <<= 24;
                s2 <<= 16;
                s1 <<= 8;
                break;
            case CDAB:
                s2 <<= 24;
                s3 <<= 16;
                s0 <<= 8;
                break;
            case ABCD:
                s0 <<= 24;
                s1 <<= 16;
                s2 <<= 8;
                break;
            case BADC:
                s1 <<= 24;
                s0 <<= 16;
                s3 <<= 8;
                break;
            default:
                //throw
                break;
        }
        //s3 <<= 24;
        //s2 <<= 16;
        //s1 <<= 8;

        s = s0 | s1 | s2 | s3;
        return s;
    }

    public static Long byteToUInt(byte[] b, int offSet, ByteOrder byteOrder) {
        return byteToInt(b, offSet, byteOrder) & 0xffffffffL;
    }

    public static Integer byteToInt(byte[] b, int offSet, ByteOrder byteOrder) {
        Integer s = 0;
        int s0 = b[offSet] & 0xff;
        int s1 = b[offSet + 1] & 0xff;
        int s2 = b[offSet + 2] & 0xff;
        int s3 = b[offSet + 3] & 0xff;
        switch (byteOrder) {
            case DCBA:
                s3 <<= 24;
                s2 <<= 16;
                s1 <<= 8;
                break;
            case CDAB:
                s2 <<= 24;
                s3 <<= 16;
                s0 <<= 8;
                break;
            case ABCD:
                s0 <<= 24;
                s1 <<= 16;
                s2 <<= 8;
                break;
            case BADC:
                s1 <<= 24;
                s0 <<= 16;
                s3 <<= 8;
                break;
            default:
                //throw
                s = null;
                break;
        }
        if (s != null) {
            s = s0 | s1 | s2 | s3;
        }
        return s;
    }

    /**
     * Convert short to byte array.
     * 低位在前
     * @param number
     * @return
     */
    public static byte[] shortToByte(short number) {
        int temp = number;
        byte[] b = new byte[2];
        for (int i = 0; i < b.length; i++) {
            b[i] = Integer.valueOf(temp & 0xff).byteValue();
            temp = temp >> 8;
        }
        return b;
    }


    public static byte[] shortToByte(short number, ByteOrder byteOrder) {
        byte[] b = new byte[2];
        if (byteOrder == ByteOrder.AB) {
            b[0] = Integer.valueOf((number >> 8) & 0xff).byteValue();
            b[1] = Integer.valueOf(number & 0xff).byteValue();
        } else if (byteOrder == ByteOrder.BA) {
            b[0] = Integer.valueOf(number & 0xff).byteValue();
            b[1] = Integer.valueOf((number >> 8) & 0xff).byteValue();
        }
        return b;
    }

    public static void shortToByte(short number, byte[] b, int offSet, ByteOrder byteOrder) {
        if (byteOrder == ByteOrder.AB) {
            b[offSet] = Integer.valueOf((number >> 8) & 0xff).byteValue();
            b[offSet + 1] = Integer.valueOf(number & 0xff).byteValue();
        } else if (byteOrder == ByteOrder.BA) {
            b[offSet] = Integer.valueOf(number & 0xff).byteValue();
            b[offSet + 1] = Integer.valueOf((number >> 8) & 0xff).byteValue();
        }
    }

    /**
     * Convert byte array to short.
     *
     * @param b
     * @return
     */
    public static Short byteToShort(byte[] b) {
        short s = 0;
        short s0 = (short) (b[0] & 0xff);
        short s1 = (short) (b[1] & 0xff);
        s1 <<= 8;
        s = (short) (s0 | s1);
        return s;
    }

    public static String byteToString(byte[] b, int offSet, ByteOrder byteOrder) {
        if (byteOrder == ByteOrder.FEDCBA) {
            return byteToHexStringFlip(b, offSet, byteOrder.size());
        } else {
            return byteToHexString(b, offSet, byteOrder.size());
        }
    }

    public static Short byteToShort(byte[] b, int offSet, ByteOrder byteOrder) {
        if (byteOrder == ByteOrder.AB) {
            return (short) (((b[offSet] & 0xff) << 8) | (b[offSet + 1] & 0xff));
        } else if (byteOrder == ByteOrder.BA) {
            return (short) (((b[offSet + 1] & 0xff) << 8) | (b[offSet] & 0xff));
        } else {
            return null;
        }
    }

    public static Integer byteToUShort(byte[] b, int offSet, ByteOrder byteOrder) {
        if (byteOrder == ByteOrder.AB) {
            return (((b[offSet] & 0xff) << 8) | (b[offSet + 1] & 0xff));
        } else if (byteOrder == ByteOrder.BA) {
            return (((b[offSet + 1] & 0xff) << 8) | (b[offSet] & 0xff));
        } else {
            return null;
        }
    }

    public static Boolean byteToBoolean(byte[] b, int offSet, int bitOffSet) {
        if (bitOffSet > 7) {
            return false;
        } else {
            int s = b[offSet] & 0xff;
            return ((s >> bitOffSet) & 1) == 1;
        }
    }

    public static Boolean byteToBoolean(byte[] b, int offSet, int bitOffSet, ByteOrder byteOrder) {
        if (bitOffSet > 15) {
            return false;
        } else {
            int st = 0x01;
            short s;
            if (byteOrder == ByteOrder.AB) {
                s = (short) (((b[offSet] & 0xff) << 8) | (b[offSet + 1] & 0xff));
            } else if (byteOrder == ByteOrder.BA) {
                s = (short) (((b[offSet + 1] & 0xff) << 8) | (b[offSet] & 0xff));
            } else {
                return null;
            }
            return ((st << bitOffSet) & s) != 0x00;
        }
    }

    public static Boolean byteToBit(byte b, int bitOffSet) {
        if (bitOffSet > 15) {
            return false;
        } else {
            int st = 0x01;
            int s = b & 0xFF;

            return ((st << bitOffSet) & s) != 0x00;
        }
    }

    /**
     * Convert double to byte array.
     *
     * @param d
     * @return
     */
    public static byte[] doubleToByte(double d) {

        return longToByte(Double.doubleToLongBits(d));
    }

    /**
     * Convert byte array to double.
     *
     * @param b
     * @return
     */
    public static double byteToDouble(byte[] b, int offset, ByteOrder byteOrder) {
        return Double.longBitsToDouble(byteToLong(b, offset, byteOrder));
    }

    /**
     * Convert float to byte array.
     *
     * @param f
     * @return
     */
    public static byte[] floatToByte(float f) {
        return intToByte(Float.floatToIntBits(f));
    }


    public static byte[] floatToByte(float f, ByteOrder byteOrder) {
        int floatInt = Float.floatToIntBits(f);
        return intToByte(floatInt, byteOrder);
    }

    /**
     * @param f
     * @param b
     * @param offSet
     * @param byteOrder
     */
    public static void floatToByte(float f, byte[] b, int offSet, ByteOrder byteOrder) {
        int floatInt = Float.floatToIntBits(f);
        intToByte(floatInt, b, offSet, byteOrder);
    }

    /**
     * Convert byte array to float.
     */
    public static Float byteToFloat(byte[] b, ByteOrder byteOrder) {
        Integer floatinit = byteToInt(b, byteOrder);
        return floatinit == null ? null : Float.intBitsToFloat(floatinit);
    }

    /**
     * Convert byte array to float.
     *
     * @param b
     * @param offSet
     * @return
     */
    public static Float byteToFloat(byte[] b, int offSet, ByteOrder byteOrder) {
        Integer floatinit = byteToInt(b, offSet, byteOrder);
        return floatinit == null ? null : Float.intBitsToFloat(floatinit);
    }

    public static String byteToHexString(byte[] b) {
        if (null == b) {
            return null;
        }
        return byteToHexString(b, 0, b.length);
    }

    public static String byteToHexString(byte b) {
        return String.format("%02X", b);
    }

    public static String byteToHexStringQuick(byte[] bytes, int offSet, int length) {
        char[] chars = new char[length * 2];
        int end = offSet + length;
        if (offSet >= 0 && length > 0 && end <= bytes.length) {
            byte h, l;
            for (int index = offSet; index < end; index++) {
                l = (byte) (bytes[index] & 0x0f);
                h = (byte) (bytes[index] >> 4 & 0x0f);
                chars[index*2 - offSet] = (char) (h > 9 ? h + 55 : h + 48);
                chars[index*2 - offSet + 1] = (char) (l > 9 ? l + 55 : l + 48);
            }
        }
        return String.valueOf(chars);
    }

    public static String byteToHexString(byte[] b, int offset, int length){
        StringBuilder sb = new StringBuilder();
        String tmp;
        int end = offset+length;
        if(offset>=0 && length>0 && end<=b.length) {
            for (int index=offset; index<end; index++) {
                tmp = Integer.toHexString(0xFF & b[index]);
                if (tmp.length() == 1) {
                    tmp = "0" + tmp;
                }
                sb.append(tmp);
            }
        }
        return sb.toString().toUpperCase();
    }


    public static String byteToHexStringTrim(byte[] b){
        int index = 0;
        for (int i = b.length - 1; i >= 0; i--) {
            if (b[i] != 0) {
                index = i + 1;
            }
        }
        return byteToHexString(b, 0, index);
    }

    public static String byteToHexStringFlip(byte[] b, int offset, int length) {
        int start = offset + length - 1;
        if(offset >= 0 && length > 0 && start < b.length) {
            StringBuilder sb = new StringBuilder();
            String tmp;
            for (int index=start; index>=offset; index--) {
                tmp = Integer.toHexString(0xFF & b[index]);
                if (tmp.length() == 1) {
                    tmp = "0" + tmp;
                }
                sb.append(tmp);
            }
            return sb.toString().toUpperCase();
        }
        return null;
    }

    public static byte[] hexStringToBytes(String str) {
        if (str.contains(" ")) {
            str = str.replaceAll(" ", "");
        }
        int length = str.length();
        if (length % 2 == 1) {
            str = "0" + str;
        }
        return hexStringToByte(str);
    }

    public static byte[] hexStringToBytesFlip(String str) {
        byte[] bytes = hexStringToBytes(str);
        reverseBytes(bytes);
        return bytes;
    }

    public static byte[] hexStringToByte(String str) {
        if (str.contains(" ")) {
            str = str.replaceAll(" ", "");
        }
        byte[] bytes = new byte[str.length() / 2];
        for (int i = 0; i < str.length() / 2; i++) {
            String subStr = str.substring(i * 2, i * 2 + 2);
            bytes[i] = (byte) Integer.parseInt(subStr, 16);
        }
        return bytes;
    }

    public static byte[] hexStringToByteQuick(String str) {
        if (str.contains(" ")) {
            str = str.replaceAll(" ", "");
        }
        byte[] bytes = new byte[str.length() / 2];
        char[] chars = str.toCharArray();
        for (int i = 0; i < bytes.length; i++) {
            bytes[i] = (byte) ((chars[i*2] > '9' ? chars[i*2] - 55 << 4 : chars[i*2] - 48 << 4) |
                    (chars[i*2+1] > '9' ? chars[i*2+1] - 55 & 0x0f : chars[i*2+1] - 48 & 0x0f));
        }
        return bytes;
    }

    public static byte[] hexStringToByteFlip(String str) {
        byte[] bytes = hexStringToByte(str);
        reverseBytes(bytes);
        return bytes;
    }

    public static void reverseBytes(byte[] bytes) {
        reverseBytes(bytes, 0, bytes.length);
    }

    /**
     * 反转字节数组
     */
    public static void reverseBytes(byte[] bytes, int start, int size) {
        int mid = size / 2;
        for (int i = start, j = 0; i < start + mid; i ++, j++) {
            int i1 = start + size - j - 1;
            bytes[i] = (byte) (bytes[i] ^ bytes[i1]);
            bytes[i1] = (byte) (bytes[i1] ^ bytes[i]);
            bytes[i] = (byte) (bytes[i] ^ bytes[i1]);
        }
    }

    /**
     * 调转双字节
     *
     * @param bytes
     * @param start
     * @param size
     */
    public static void reverseDoubleByte(byte[] bytes, int start, int size) {
        for (int i = start; i < size + start; i += 2) {
            bytes[i] = (byte) (bytes[i] ^ bytes[i + 1]);
            bytes[i + 1] = (byte) (bytes[i + 1] ^ bytes[i]);
            bytes[i] = (byte) (bytes[i] ^ bytes[i + 1]);
        }
    }

    /**
     * bcd定点数转换
     *
     * @param bcd 数组
     * @param start 起始
     * @param length 长度
     * @param order 字节顺序
     * @param radix 进制
     * @param fraction 小数位
     * @return
     */
    public static float bcdFixNumber(byte[] bcd, int start, int length, boolean order, int radix, int fraction) {
        if (order) {
            return (float) (Integer.parseInt(byteToHexString(bcd, start, length), radix) / Math.pow(10, fraction));
        } else {
            return Integer.parseInt(byteToHexStringFlip(bcd, start, length), radix) / (float) fraction;
        }
    }

    public static int bcdToInt(byte[] bcd, int start, int length, boolean order) {
        int res = 0;
        if (order) {
            for (int i = start; i < start + length; i++) {
                res = getRes(bcd, res, i);
            }
        } else {
            for (int i = start + length - 1; i >= start; i--) {
                res = getRes(bcd, res, i);
            }
        }
        return res;
    }

    public static int bcdToInt(byte data) {
        int res = 0;
        int t;
        t = data >> 4 & 0x0f;
        res *= 10;
        res += t;
        t = data & 0x0f;
        res *= 10;
        res += t;
        return res;
    }

    private static int getRes(byte[] bcd, int res, int i) {
        int t;
        t = bcd[i] >> 4 & 0x0f;
        res *= 10;
        res += t;
        t = bcd[i] & 0x0f;
        res *= 10;
        res += t;
        return res;
    }

    /**
     * @param bcd
     * @param start
     * @param integer
     * @param order   true:低前高后 false:高前低后 （和其他bcd解码不同）
     */
    public static void intToBcd(byte[] bcd, int start, int integer, boolean order) {
        int i = 0;
        int low;
        if (order) {
            while (integer > 0) {
                low = integer % 10;
                integer = integer / 10;
                bcd[i + start] = (byte) (low + (integer % 10 << 4));
                i++;
                integer = integer / 10;
            }
        } else {
            int tmp = integer;
            while (tmp > 0) {
                tmp = tmp / 100;
                i++;
            }
            i--;
            while (integer > 0) {
                low = integer % 10;
                integer = integer / 10;
                bcd[i + start] = (byte) (low + (integer % 10 << 4));
                i--;
                integer = integer / 10;
            }
        }
    }

    public static String bcd2str(byte[] bcd, int offSet, int length, boolean order) {
        if (null == bcd || bcd.length == 0) {
            return "";
        } else {
            // 存储转码后的字符串
            StringBuilder sb = new StringBuilder();
            // 循环数组解码
            if (order) {
                for (int i = offSet; i < offSet + length; i++) {
                    // 转换高字节
                    int high = ((bcd[i] & 0xf0) >> 4);
                    sb.append(Integer.toHexString(high));
                    // 转换低字节
                    int low = (bcd[i] & 0x0f);
                    sb.append(Integer.toHexString(low));
                }
            } else {
                for (int i = offSet + length - 1; i >= offSet; i--) {
                    // 转换高字节
                    int high = ((bcd[i] & 0xf0) >> 4);
                    sb.append(Integer.toHexString(high));
                    // 转换低字节
                    int low = (bcd[i] & 0x0f);
                    sb.append(Integer.toHexString(low));
                }
            }
            // 返回解码字符串
            return sb.toString();
        }
    }

    public static char[] bcd2charArr(byte[] bcd, int offSet, int length, boolean order) {
        char[] chars;
        if (null == bcd || bcd.length == 0) {
            return null;
        } else {
            chars = new char[length * 2];
            int j = 0;
            if (order) {
                for (int i = offSet; i < offSet + length; i++) {
                    j = getJ(bcd, chars, j, i);
                }
            } else {
                for (int i = offSet + length - 1; i >= offSet; i--) {
                    j = getJ(bcd, chars, j, i);
                }
            }
            return chars;
        }
    }

    private static int getJ(byte[] bcd, char[] chars, int j, int i) {
        int high = ((bcd[i] & 0xf0) >> 4);
        char c = high == 0x0a ? '-' : (char) (high + 0x30);
        chars[j++] = c;
        int low = (bcd[i] & 0x0f);
        c = low == 0x0a ? '-' : (char) (low + 0x30);
        chars[j++] = c;
        return j;
    }

    /**
     * 将十进制两位数转为同等字面大小的hex字节 例：12 -> 0x12
     *
     * @param num
     * @return
     */
    public static byte tensToLiteralEqualHex(int num) {
        int tens = num / 10;
        int digit = num - tens * 10;
        return (byte) ((tens << 4) + digit);
    }

    /**
     * 将十进制数字符串转为同等字面大小的bcd串
     *
     * @param bcd
     * @param tenstring
     * @param offset
     * @param order true 升序，false 倒序
     */

    public static void tenstringToBcd(byte[] bcd, String tenstring, int offset, boolean order) {
        for (int i = 0; i < tenstring.length(); ) {
            if (order) {
                bcd[offset++] = tensToLiteralEqualHex(Integer.parseInt(tenstring.substring(i, i + 2)));
                i += 2;
            } else {
                bcd[offset++] = tensToLiteralEqualHex(Integer.parseInt(tenstring.substring(tenstring.length() - i - 2, tenstring.length() - i)));
                i += 2;
            }
        }
    }


    public static void stringToBcd(byte[] bcd, String tenstring, int offset, boolean order) {
        byte[] bytes = ByteUtil.hexStringToByte(tenstring);
        int length = bytes.length;
        for (int i = 0; i < length; i++) {
            if (order) {
                bcd[offset++] = bytes[i];
            } else {
                bcd[offset++] = bytes[length-1-i];
            }
        }
    }

    public static byte sum(byte[] data, int offset, int len) {
        byte s = 0;
        int end = offset + len;
        for (int i = offset; i < end; i++) {
            if (i >= data.length) {
                break;
            }
            s += data[i];
        }
        return s;
    }

    public static byte xorSum(byte[] data, int offset, int len) {
        byte s = 0;
        int end = offset + len;
        for (int i = offset; i < end; i++) {
            if (i >= data.length) {
                break;
            }
            s ^= data[i];
        }
        return s;
    }

    //b为传入的字节，i为第几位（范围0-7），如要获取bit0，则i=0
    public static int getByBit(byte b, int i) {
        return (b >> i) & 0x1;
    }

    //b为传入的字节，start是起始位，length是长度，如要获取bit0-bit4的值，则start为0，length为5
    public static int getByBits(byte b, int start, int length) {
        return (b >> start) & (0xFF >> (8 - length));
    }

    /**
     * 将byte转换为一个长度为8的byte数组，数组每个值代表bit
     */
    public static byte[] getBits(byte b) {
        byte[] array = new byte[8];
        for (int i = 7; i >= 0; i--) {
            array[i] = (byte) (b & 1);
            b = (byte) (b >> 1);
        }
        return array;
    }

    public static boolean byteArrayEqual(byte[] a ,int aStart,byte[] b,int bStart,int len){
        for (int i = 0; i < len; i++) {
            if (a[aStart + i] != b[bStart + i]) {
                return false;
            }
        }
        return true;
    }

    /**
     * 根据IEEE规则将单精度浮点数转成对应的4字节整数
     * @param f
     * @return
     * @Author zhuj
     */
    public static int floatToBinInt(float f) {
        //取整数部分
        int r = 0;
        int s = (int) Math.abs(f);
        int index = 0;
        boolean key = false;
        for (int i=1;i<32;i++){
            if (!key && ((s >> 31-i)&0x01) == 0x01) key=true;
            if(key) {
                r |= (((s >> 31-i-1)&0x01) << (22-index++));
            }
        }
        //取小数部分
        float dd = Math.abs(f - ((int)f));
        for (int i=0;i<24-index;i++){
            dd = dd * 2;
            r |= ((byte)dd<<(23 - index - i));
            dd = dd>1?dd-1:dd;
        }
        //阶数
        int ex = (127+index-1) << 23;
        r = f>0 ? r|ex : (r|ex)|0x80000000;
        return r;
    }

    /**
     * 根据IEEE规则将4字节整数转为对应单精度浮点数
     * @param num
     * @return
     * @Author zhuj
     */
    public static float binIntToFloat(int num) {
        int b = (num >> 23)&0xff;
        int ex = b - 127;
        int data = num | 0x800000;
        float f = 0;
        for (int i=0;i<24;i++) {
            if (i < ex)
                f += ((data >> (23-i))&0x01) * (Math.pow(2, ex-i));
            else
                f += ((data >> (23-i))&0x01) * (Math.pow(2, -(i-ex)));
        }
        return num>0 ? f : -f;
    }

    /**
     * 根据IEEE规则将双精度浮点数转成对应的8字节长整数
     * @param d
     * @return
     * @Author zhuj
     */
    public static long doubleToBinLong(double d) {
        //取整数部分
        long r = 0;
        long s = (long) Math.abs(d);
        int index = 0;
        boolean key = false;
        for (int i=1;i<32;i++){
            if (((s >> 31-i)&0x01) == 0x01 && !key) key=true;
            if(key) {
                r |= (((s >> 31-i-1)&0x01) << (51-index++));
            }
        }
        //取小数部分
        double dd = Math.abs(d - ((int)d));
        for (int i=0;i<54-index;i++){
            dd = dd * 2;
            r |= ((long) dd<<(52 - index - i));
            dd = dd>1?dd-1:dd;
        }
        //阶数
        long ex = ((long)(1023+index-1)) << 52;
        long l80 = 1;
        r = d>0 ? r|ex : (r|ex)|l80<<63;
        return r;
    }

    /**
     * 根据IEEE规则将8字节长整数转为对应双精度浮点数
     * @param num
     * @return
     * @Author zhuj
     */
    public static double binLongToDouble(long num) {
        int b = (int) ((num >> 52)&0x7ff);
        int ex = b - 1023;
        long l10 = (long) 1<<52;
        long data = num | l10;
        double d = 0;
        for (int i=0;i<53;i++) {
            if (i < ex)
                d += ((data >> (52-i))&0x01) * (Math.pow(2, ex-i));
            else
                d += ((data >> (52-i))&0x01) * (Math.pow(2, -(i-ex)));
        }
        return num>0 ? d : -d;
    }

    public static void main(String[] args) {
        String s = "33359B53748473C33433333737067D67BBFF49";
        byte[] bytes = ByteUtil.hexStringToBytes(s);
        for (int i = 0; i < bytes.length; i++) {
            bytes[i] = (byte)((bytes[i] - 0x33) & 0xff);
        }
        System.out.println(ByteUtil.byteToHexString(bytes));
    }


    public static void setData(byte[] b) {
        b = new byte[1];
        b[0] = 1;
    }



    /**
     * 字节字符串中所有字节减字节
     * @param s
     * @param b
     */
    public static byte[] byteSubByte(String s, byte b) {
        byte[] bytes = ByteUtil.hexStringToByte(s);
        return byteSubByte(bytes, b);
    }

    /**
     * 字节字符串中所有字节减字节
     * @param bytes
     * @param b
     */
    public static byte[] byteSubByte(byte[] bytes, byte b) {
        byte[] data = new byte[bytes.length];
        for (int i = 0; i < bytes.length; i++) {
            data[i] = (byte)((bytes[i] - b) & 0xff);
        }
        return data;
    }


}
